package com.ruoyi.system.utils;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.SM3;
import com.ruoyi.common.utils.SM4;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.config.ApiConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.validation.constraints.NotNull;
import java.io.*;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Arrays;
import java.util.Objects;

/**
 * @Description: TODO
 * @author: wangp
 * @date: 2025年01月15日 16:52
 */

@Component
public class HttpApi {

    @Autowired
    ApiConfig apiConfig;


    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);

    public static String sendSSLApi(String prodCode, String requestRefId, String secretId,String secretKey, String url, String param) {

        StringBuilder result = new StringBuilder();
        log.info("sendSSLPost - prodCode-{},  requestRefId-{},  secretId-{}, secretKey-{},  url-{},  param-{}",  prodCode,  requestRefId,  secretId, secretKey,  url,  param);
        String urlNameString = url + prodCode;
        log.info("sendSSLPost - urlNameString-{}",  urlNameString);

        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new HttpUtils.TrustAnyTrustManager()}, new java.security.SecureRandom());
            URL console = new URL(urlNameString);
            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("Content-Type", "application/json");
            // 请求签名
            conn.setRequestMethod("POST");
//            conn.setRequestProperty("requestRefId", requestRefId);
//            conn.setRequestProperty("secretId", secretId);
//            String format = String.format("requestRefId=%s&secretId=%s", requestRefId, secretId);
//            String signature = SM3.encrypt(format, secretKey);
//            conn.setRequestProperty("signature", signature);

            log.info("sendSSLApi head - requestRefId:{} - secretId:{}", requestRefId, secretId);
            // 准备要发送的 JSON 数据
            String jsonData = generateRequestData(param, requestRefId, secretId, secretKey);
            log.info("sendSSLApi request - {}", jsonData);

            conn.setDoOutput(true);
            conn.setDoInput(true);

            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier(new HttpUtils.TrustAnyHostnameVerifier());
            conn.connect();

            // 将 JSON 数据写入输出流
            try (OutputStream os = conn.getOutputStream()) {
                byte[] input = jsonData.getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
                os.flush();
            }

            // 获取响应状态码
            int responseCode = conn.getResponseCode();
            System.out.println("Response Code: " + responseCode);

            // 读取响应内容
            try (BufferedReader br = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "utf-8"))) {
                String responseLine;
                while ((responseLine = br.readLine()) != null) {
                    result.append(responseLine.trim());
                }
                System.out.println("Response: " + result.toString());
            }
            log.info("recv - {}", result);
            conn.disconnect();
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
        }
        return result.toString();
    }

    public static String sendCommonSSLApi(String prodCode, String url, String contentType, JSONObject head,JSONObject request) {
        StringBuilder result = new StringBuilder();
        log.info("sendSSLPost - prodCode-{},  head-{},  url-{}", prodCode, head, url);
        String urlNameString = url + prodCode;
        log.info("sendSSLPost - urlNameString-{}", urlNameString);

        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new HttpUtils.TrustAnyTrustManager()}, new java.security.SecureRandom());
            URL console = new URL(urlNameString);
            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();

            conn.setRequestProperty("x-bq-requestrefid", head.getString("x-bq-requestrefid"));
            conn.setRequestProperty("x-bq-secretid", head.getString("x-bq-secretid"));
            conn.setRequestProperty("x-bq-requesttime", head.getString("x-bq-requesttime"));
            conn.setRequestProperty("x-bq-signature", head.getString("x-bq-signature"));
            log.info("conn:{}", conn);
            // 请求签名
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("Content-Type", contentType);
            conn.setRequestMethod("POST");

            log.info("sendSSLApi head:{}", head);
            // 准备要发送的 JSON 数据
//            JSONObject jsonData = generateCommonRequestData(head, request);
            // log.info("sendSSLApi request - {}", jsonData);

            conn.setDoOutput(true);
            conn.setDoInput(true);

            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier(new HttpUtils.TrustAnyHostnameVerifier());
            conn.connect();

            // 将 JSON 数据写入输出流
            try (OutputStream os = conn.getOutputStream()) {
                byte[] input = request.toJSONString().getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
                os.flush();
            }

            // 获取响应状态码
            int responseCode = conn.getResponseCode();
            log.info("Response Code:{} ", responseCode);

            // 读取响应内容
            try (BufferedReader br = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "utf-8"))) {
                String responseLine;
                while ((responseLine = br.readLine()) != null) {
                    result.append(responseLine.trim());
                }
            }
            log.info("recv - {}", result);
            conn.disconnect();
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + head, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + head, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + head, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + head, e);
        }
        return result.toString();
    }


    public static String sendBatchSSLApi(String prodCode, String requestRefId, String secretId,String secretKey, String url, String zipFilePath) {

        StringBuilder result = new StringBuilder();
        log.info("sendSSLPost - prodCode-{},  requestRefId-{},  secretId-{}, secretKey-{},  url-{},  zipFilePath-{}",  prodCode,  requestRefId,  secretId, secretKey,  url,  zipFilePath);
        String urlNameString = url + prodCode;
        log.info("sendSSLPost - urlNameString-{}",  urlNameString);
        // 创建边界
        String boundary = "------------------------" + IdUtils.fastSimpleUUID();

        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new HttpUtils.TrustAnyTrustManager()}, new java.security.SecureRandom());
            URL console = new URL(urlNameString);
            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("Content-Type", "application/json");
            // 请求签名
            conn.setRequestMethod("POST");
            long unixTimeMillis = Instant.now().toEpochMilli() / 1000;
            String format = String.format("x-bq-requestrefid=%s&x-bq-secretid=%s&x-bq-requesttime=%d", requestRefId, secretId, unixTimeMillis);
            String signature = SM3.encrypt(format, secretKey);
            conn.setRequestProperty("x-bq-requestrefid", requestRefId);
            conn.setRequestProperty("x-bq-secretid", secretId);
            conn.setRequestProperty("x-bq-requesttime", String.valueOf(unixTimeMillis));

            conn.setRequestProperty("x-bq-signature", signature);

            log.info("sendSSLApi head - requestRefId:{} - secretId:{} - requesttime:{} - signature:{}", requestRefId, secretId, unixTimeMillis, signature);

            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

            conn.setDoOutput(true);
            conn.setDoInput(true);

            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier(new HttpUtils.TrustAnyHostnameVerifier());
            conn.connect();

            try (OutputStream output = conn.getOutputStream();
                 PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8), true)) {

                // 添加文本参数
                String[] apis = {"AME000964", "AME000965"};
                for (String api : apis) {
                    writer.append("--").append(boundary).append("\r\n");
                    writer.append("Content-Disposition: form-data; name=\"apis\"\r\n\r\n");
                    writer.append(api).append("\r\n");
                }

                // 添加文件参数
                writer.append("--").append(boundary).append("\r\n");
                writer.append("Content-Disposition: form-data; name=\"files\"; filename=\"" + FileUtils.getName(zipFilePath) + "\"\r\n");
                writer.append("Content-Type: application/zip\r\n\r\n");
                writer.flush();

                try (FileInputStream fileInput = new FileInputStream(zipFilePath)) {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = fileInput.read(buffer)) != -1) {
                        output.write(buffer, 0, bytesRead);
                    }
                    output.flush();
                }

                writer.append("\r\n");
                writer.append("--").append(boundary).append("--\r\n");
            }

            // 获取响应
            int responseCode = conn.getResponseCode();
            System.out.println("Response Code: " + responseCode);

            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "utf-8"))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
                log.info("recv - {}", result);
            }

            conn.disconnect();
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + zipFilePath, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + zipFilePath, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + zipFilePath, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + zipFilePath, e);
        }
        return result.toString();
    }

    public static String saveFileSSLApi(String prodCode, String url, String contentType, JSONObject head,JSONObject request, String savePath) {

        log.info("sendSSLPost - prodCode-{},  head-{},  url-{}", prodCode, head, url);
        String urlNameString = url + prodCode;
        log.info("sendSSLPost - urlNameString-{}",  urlNameString);

        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new HttpUtils.TrustAnyTrustManager()}, new java.security.SecureRandom());
            URL console = new URL(urlNameString);
            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("Content-Type", contentType);
            // 请求签名
            conn.setRequestMethod("POST");
            conn.setRequestProperty("x-bq-requestrefid", head.getString("x-bq-requestrefid"));
            conn.setRequestProperty("x-bq-secretid", head.getString("x-bq-secretid"));
            conn.setRequestProperty("x-bq-requesttime", head.getString("x-bq-requesttime"));
            conn.setRequestProperty("x-bq-signature", head.getString("x-bq-signature"));

            log.info("sendSSLApi head:{}", head);
            // 准备要发送的 JSON 数据
            JSONObject jsonData = generateCommonRequestData(head, request);

            conn.setDoOutput(true);
            conn.setDoInput(true);

            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier(new HttpUtils.TrustAnyHostnameVerifier());
            conn.connect();

            // 将 JSON 数据写入输出流
            try (OutputStream os = conn.getOutputStream()) {
                byte[] input = request.toJSONString().getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
                os.flush();
            }

            // 获取响应状态码
            int responseCode = conn.getResponseCode();
            System.out.println("Response Code: " + responseCode);

            // 4. 获取输入流并创建输出文件
            File saveFile = new File(savePath);
            FileUtil.mkParentDirs(saveFile);
            try(InputStream in = conn.getInputStream();
            FileOutputStream out = new FileOutputStream(saveFile)){
                // 5. 使用缓冲区读写数据（高效处理大文件） // 8KB缓冲区
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }

                log.info("文件下载完成，保存路径: " + saveFile.getAbsolutePath());
            }

            log.info("savePath - {}", savePath);
            conn.disconnect();
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + head, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + head, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + head, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + head, e);
        }
        return savePath;
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url 发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String prodCode, String requestRefId, String secretId,String secretKey,String url, String param)
    {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try
        {
            log.info("sendPost - {}", url + prodCode);
            URL realUrl = new URL(url + prodCode);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("Content-Type", "application/json");

            // 请求签名
            conn.setRequestProperty("requestRefId", requestRefId);
            conn.setRequestProperty("secretId", secretId);
            String format = String.format("requestRefId=%s&secretId=%s", requestRefId, secretId);
            String signature = SM3.encrypt(format, secretKey);
            conn.setRequestProperty("signature", signature);

            log.info("sendPost head - requestRefId:{} - secretId:{} - signature:{}", requestRefId,secretId,signature);
            String s = generateRequestData(param, requestRefId, secretId, secretKey);
            log.info("sendPost request - {}", s);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(s);
            out.flush();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            String line;
            while ((line = in.readLine()) != null)
            {
                result.append(line);
            }
            log.info("recv - {}", result);
        }
        catch (ConnectException e)
        {
            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        }
        catch (IOException e)
        {
            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
        }
        finally
        {
            try
            {
                if (out != null)
                {
                    out.close();
                }
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException ex)
            {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    public static void main(String[] args) {

    }

    public static String generateRequestData(String param, String requestRefId, String secretId,String secretKey) {

        String format = String.format("requestRefId=%s&secretId=%s", requestRefId, secretId);
        String signature = SM3.encrypt(format, secretKey);

        // 构建请求报文
        String encrypt = SM4.encrypt(param, secretKey);
        String requestJson = String.format("{\"head\": {\"requestRefId\": \"%s\", \"secretId\": \"%s\", \"signature\": \"%s\"}, \"request\": \"%s\"}",
                requestRefId, secretId, signature, encrypt);
        log.info("param{}", param);

        return requestJson;
    }

    public static JSONObject generateFileRequestData(String requestRefId, String secretId, String secretKey, MultipartFile file) {
        JSONObject head = generateHead(requestRefId, secretId, secretKey);
        JSONObject js = JSONObject.of("head", head,
                "request", JSONObject.of("apis", Arrays.asList("AME000964", "AME000965"), "files", file));

        log.info("head{}", head);

        return js;
    }

    public static JSONObject generateCommonRequestData(JSONObject head,JSONObject request) {
        return JSONObject.of("head", head, "request", request);
    }

    @NotNull
    public static JSONObject generateHead(String requestRefId, String secretId, String secretKey) {
        long unixTimeMillis = Instant.now().toEpochMilli() / 1000;
        String format = String.format("x-bq-requestrefid=%s&x-bq-secretid=%s&x-bq-requesttime=%d", requestRefId, secretId, unixTimeMillis);
        String signature = SM3.encrypt(format, secretKey);

        // 构建请求报文
        JSONObject head = JSONObject.of("x-bq-requestrefid", requestRefId, "x-bq-secretid", secretId, "x-bq-requesttime", unixTimeMillis, "x-bq-signature", signature);
        return head;
    }

    public static String sendRequest(String requestData, String prodCode, String url) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        log.info("sendRequest: url-{}", url + prodCode);
        HttpPost httpPost = new HttpPost(url + prodCode);
        httpPost.setEntity(new StringEntity(requestData, StandardCharsets.UTF_8));
        httpPost.setHeader("Content-Type", "application/json");

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("sendRequest: url-{}; prodCode-{}; requestData-{}", url, prodCode, requestData, e);
            return "";
        }

    }

}
